package com.personal.dao.metadata;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import com.personal.dao.annotation.DataBaseField;
import com.personal.dao.annotation.DataBasePrimaryKey;
import com.personal.dao.annotation.DataBaseTable;
import com.personal.dao.annotation.Validator;
import com.personal.dao.exception.IllegalAnnotationException;
import com.personal.dao.util.DaoUtil;

/**
 * DataBaseTableMetadata
 * 
 * @author cuibo
 *
 */
public class DataBaseTableMetadata<T> implements Serializable
{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	/** 类 */
	private Class<T> c;

	/** 表名 */
	private String tableName;

	/** 是否有大字段 */
	private boolean hasBigData;

	/** 主键 */
	private DataBasePrimaryKeyMetadata primaryKey;

	/** 列（不包括主键列表） */
	private List<DataBaseFieldMetadata> fields;

	/** 列，用于查找快速:key 统一使用小写 */
	private Map<String, DataBaseFieldMetadata> fieldMap;

	/** 列，用于查找快速:key 统一使用小写 */
	private Map<String, DataBaseFieldMetadata> columnMap;

	/**
	 * 通过fieldName获取列的元数据
	 * 
	 * @param fieldName
	 * @return
	 */
	public DataBaseFieldMetadata getDataBaseFieldMetadataByFieldName(String fieldName)
	{
		return fieldMap == null ? null : fieldMap.get(fieldName);
	}

	/**
	 * 通过columnName获取列的元数据
	 * 
	 * @param columnName
	 * @return
	 */
	public DataBaseFieldMetadata getDataBaseFieldMetadataByColumnName(String columnName)
	{
		return columnMap == null ? null : columnMap.get(columnName);
	}

	/**
	 * 通过类型初始化该类型的元数据
	 * 
	 * @param t
	 */
	public void initByBaseModel(Class<T> t)
	{
		this.c = t;
		// 获取类注解
		DataBaseTable table = t.getAnnotation(DataBaseTable.class);
		if (table == null)
		{
			throw new IllegalAnnotationException(t + "缺少DataBaseTable注解！");
		}
		this.tableName = DaoUtil.isEmpty(table.tableName()) ? t.getSimpleName() : table.tableName();
		this.fields = new ArrayList<DataBaseFieldMetadata>();
		this.fieldMap = new HashMap<String, DataBaseFieldMetadata>();
		this.columnMap = new HashMap<String, DataBaseFieldMetadata>();
		// 获取所有属性
		Field[] fields = t.getDeclaredFields();
		for (Field field : fields)
		{
			DataBasePrimaryKey primaryKey = field.getAnnotation(DataBasePrimaryKey.class);
			if (this.primaryKey != null && primaryKey != null)
			{
				throw new IllegalAnnotationException(t + "的DataBasePrimaryKey主键注解只能唯一！");
			}
			// 列的校验
			Validator validator = field.getAnnotation(Validator.class);
			ValidatorMetadata validatorMetadata = null;
			if (validator != null)
			{
				validatorMetadata = new ValidatorMetadata();
				validatorMetadata.init(validator);
			}
			if (primaryKey != null)
			{
				this.primaryKey = new DataBasePrimaryKeyMetadata();
				this.primaryKey.init(field, primaryKey);
				// 统一用于小写存储，拿的时候不区分大小写
				this.fieldMap.put(this.primaryKey.getFieldName().toLowerCase(Locale.ENGLISH), this.primaryKey);
				this.columnMap.put(this.primaryKey.getColumnName().toLowerCase(Locale.ENGLISH), this.primaryKey);
				// 设置校验
				this.primaryKey.setValidator(validatorMetadata);
				continue;
			}
			DataBaseField dataBaseField = field.getAnnotation(DataBaseField.class);
			// 字段是否过期
			Deprecated deprecated = field.getAnnotation(Deprecated.class);
			if (dataBaseField != null)
			{
				DataBaseFieldMetadata fm = new DataBaseFieldMetadata();
				fm.init(field, dataBaseField, deprecated);
				// 设置校验
				fm.setValidator(validatorMetadata);
				this.fields.add(fm);
				
				// 判断是否有大数据
				if (fm.isBigData())
				{
					this.hasBigData = true;
				}
			}
		}
		if (this.fields.isEmpty())
		{
			throw new IllegalAnnotationException(t + "合法列为空！");
		}
		for (DataBaseFieldMetadata field : this.fields)
		{
			// 统一用于小写存储，拿的时候不区分大小写
			this.fieldMap.put(field.getFieldName().toLowerCase(Locale.ENGLISH), field);
			this.columnMap.put(field.getColumnName().toLowerCase(Locale.ENGLISH), field);
		}
	}

	public String getTableName()
	{
		return tableName;
	}

	public DataBasePrimaryKeyMetadata getPrimaryKey()
	{
		return primaryKey;
	}

	public List<DataBaseFieldMetadata> getFields()
	{
		return Collections.unmodifiableList(fields);
	}

	public boolean isHasBigData()
	{
		return hasBigData;
	}

	public Class<T> getC()
	{
		return c;
	}

}
